use std::io::Write;

use bevy::log::info;
use bincode;
use bincode::{Decode, Encode, config};

/// 持久化数据
pub struct Persistence {
    pub save_path: String,
    pub config: config::Configuration,
}

impl Persistence {
    pub fn new(save_path: String) -> Self {
        Self {
            save_path,
            config: config::standard(),
        }
    }

    /// 保存数据到文件
    pub fn save<T: Encode + ?Sized>(&self, data: &T) -> Result<(), Box<dyn std::error::Error>> {
        let file = std::fs::File::create(&self.save_path)?;
        let mut writer = std::io::BufWriter::new(file);
        bincode::encode_into_std_write(data, &mut writer, self.config)?;
        writer.flush()?;
        Ok(())
    }

    /// 从文件加载数据
    pub fn load<T: Decode<()>>(&self) -> Result<T, Box<dyn std::error::Error>> {
        let file = std::fs::File::open(&self.save_path)?;
        let metadata = file.metadata()?;
        if metadata.len() == 0 {
            return Err(Box::new(std::io::Error::new(
                std::io::ErrorKind::UnexpectedEof,
                "存档文件为空",
            )));
        }
        let mut reader = std::io::BufReader::new(file);
        let data: T = bincode::decode_from_std_read(&mut reader, self.config)?;
        Ok(data)
    }
}

/// 持久化特性
pub trait Saved: Decode<()> + Encode + Sized {
    /// 获取默认值
    fn get_def() -> Self;

    /// 保存数据到文件
    fn save(&self)
    where
        Self: Encode,
    {
        let full_name = Self::sanitized_type_name();
        Persistence::new(format!("./assets/gameDb/{}.bin", full_name))
            .save(self)
            .unwrap_or_else(|_| println!("保存{}失败！", full_name));
    }

    /// 从文件加载数据
    fn load() -> Self {
        let full_name = Self::sanitized_type_name();
        Persistence::new(format!("./assets/gameDb/{}.bin", full_name))
            .load()
            .unwrap_or_else(|_| {
                info!("加载{}失败！", full_name);
                Self::get_def()
            })
    }

    /// 获取类型名称并替换 `::` 为 `_`
    fn sanitized_type_name() -> String {
        std::any::type_name::<Self>().replace("::", "_")
    }
}

// 持久化特性
// pub trait SavedDef: Decode<()> + Encode + Sized + Default {
//     /// 保存数据到文件
//     fn save(&self)
//     where
//         Self: Encode,
//     {
//         let full_name = Self::sanitized_type_name();
//         Persistence::new(format!("./assets/gameDb/{}.bin", full_name))
//             .save(self)
//             .unwrap_or_else(|_| println!("保存{}失败！", full_name));
//     }

//     /// 从文件加载数据
//     fn load() -> Self {
//         let full_name = Self::sanitized_type_name();
//         Persistence::new(format!("./assets/gameDb/{}.bin", full_name))
//             .load()
//             .unwrap_or_else(|_| {
//                 println!("加载{}失败！", full_name);
//                 Self::default()
//             })
//     }

//     /// 获取类型名称并替换 `::` 为 `_`
//     fn sanitized_type_name() -> String {
//         std::any::type_name::<Self>().replace("::", "_")
//     }
// }
